package tr.com.softoval.beanscanner.generator;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;

import tr.com.softoval.beanscanner.api.BeanCandidateException;
import tr.com.softoval.beanscanner.config.BeanCandidateLiterals;
import tr.com.softoval.beanscanner.util.Utils;

public class BeanCandidateFilter {
	private MetadataReaderFactory    	metadataReaderFactory;
	private BeanCandidateLiterals 		literals;
	private List<TypeFilter> 			abstractFilter;
	private List<TypeFilter> 			interfaceFilter;
	private List<TypeFilter> 			annotationFilter;
	
	public static final BeanCandidateFilter getInstance() {
		return new BeanCandidateFilter();
	}
	
	private BeanCandidateFilter() {
		this.abstractFilter = new ArrayList<TypeFilter>();
		this.interfaceFilter = new ArrayList<TypeFilter>();
		this.annotationFilter = new ArrayList<TypeFilter>();
	}
	
	public void generateDeclaredFilters() throws ClassNotFoundException {
		for (String abstractLiteral : literals.getAbstractLiterals()) {
			Class<?> clazz = Class.forName(abstractLiteral);
			this.abstractFilter.add(new AssignableTypeFilter(clazz));
			Utils.log("Assignable Filter : " + clazz.getName());
		}
		
		for (String interfaceLiteral : literals.getInterfaceLiterals()) {
			Class<?> clazz = Class.forName(interfaceLiteral);
			this.interfaceFilter.add(new AssignableTypeFilter(clazz));
			Utils.log("Assignable Filter : " + clazz.getName());
		}
		
		for (String annotationLiteral : literals.getAnnotationLiterals()) {
			Class<? extends Annotation> clazz = (Class<? extends Annotation>) Class.forName(annotationLiteral);
			this.annotationFilter.add(new AnnotationTypeFilter(clazz));
			Utils.log("Annotation Filter : " + clazz.getName());
		}
	}
	
	public Boolean isMatchOverFilters(MetadataReader metadataReader) {
		try {
			for (TypeFilter filter : this.abstractFilter) {
				if (filter.match(metadataReader, metadataReaderFactory)) {
					return Boolean.TRUE;
				}
			}
			
			for (TypeFilter filter : this.annotationFilter) {
				if (filter.match(metadataReader, metadataReaderFactory)) {
					return Boolean.TRUE;
				}
			}
			
			for (TypeFilter filter : this.interfaceFilter) {
				if (filter.match(metadataReader, metadataReaderFactory)) {
					return Boolean.TRUE;
				}
			}
		} catch (Exception e) {
			throw new BeanCandidateException(e);
		}
		
		return Boolean.FALSE;
	}
	
	
	public Boolean isInstantiatableClass(Class<?> clazz) {
		if (literals.getAbstractLiterals().contains(clazz.getName())) {
			return Boolean.FALSE;
		} else if (literals.getInterfaceLiterals().contains(clazz.getName())) {
			return Boolean.FALSE;
		} else if (literals.getAnnotationLiterals().contains(clazz.getName())) {
			return Boolean.FALSE;
		}
		return Boolean.TRUE;
	}
	
	
	public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
		this.metadataReaderFactory = metadataReaderFactory;
	}
	
	public void setBeanCandidateLiterals(BeanCandidateLiterals literals) {
		this.literals = literals;
	}
	

}
